package cn.hill4j.tool.spring.ext.core;


import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.CollectionUtils;

import java.util.Set;
/**
  * ClassName: AbstractRegistrar
  * Description: spring beanDefinition信息注册器超类
  * @author hillchen
  * Date 2023/8/8
  * @version: 1.0
  */
public abstract class AbstractRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private ResourceLoader resourceLoader;

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
    /**
     * @author hillchen
     * Description: 定义springbean扫描器
     * Date 2023/8/8 23:24
     * @return ClassPathScanningCandidateComponentProvider
     **/
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
            @Override
            protected boolean isCandidateComponent(
                    AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }
    /**
     * @author hillchen
     * Description: 获取springbean扫描基础包
     * Date 2023/8/8 23:24
     * @param importingClassMetadata 注解元数据
     * @return Set
     **/
    protected abstract Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) ;
    /**
     * @author hillchen
     * Description: 定义springbean过去器
     * Date 2023/8/8 23:25
     * @return Set
     **/
    protected abstract Set<TypeFilter> initBeanFilter();

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(this.resourceLoader);
        Set<String> basePackages;
        basePackages = getBasePackages(metadata);
        Set<TypeFilter> typeFilters = initBeanFilter();
        if (!CollectionUtils.isEmpty(typeFilters)){
            typeFilters.forEach(typeFilter -> scanner.addIncludeFilter(typeFilter));
        }
        beforeRegisterBeanDefinitions(metadata, registry);

        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidateComponents = scanner
                    .findCandidateComponents(basePackage);
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    // verify annotated class is an interface
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    registerBeans(annotationMetadata,registry,environment);
                }
            }
        }
        afterRegisterBeanDefinitions(metadata, registry);
    }
    /**
     * @author hillchen
     * Description: springbean BeanDefinitions注册前置操作
     * Date 2023/8/8 23:26
     * @param metadata 注解元数据
     * @param registry BeanDefinitions注册器
     **/
    protected void beforeRegisterBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry){}

    /**
     * @author hillchen
     * Description: springbean BeanDefinitions注册后置操作
     * Date 2023/8/8 23:27
     * @param metadata 注解元数据
     * @param registry BeanDefinitions注册器
     **/
    protected void afterRegisterBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry){}

    /**
     * @author hillchen
     * Description: springbean BeanDefinitions注册操作
     * Date 2023/8/8 23:27
     * @param metadata 注解元数据
     * @param registry BeanDefinitions注册器
     * @param environment 环境上下文
     **/
    protected abstract void registerBeans(AnnotationMetadata metadata,BeanDefinitionRegistry registry,Environment environment) ;
    /**
     * @author hillchen
     * Description: 获取资源配置加载器
     * Date 2023/8/8 23:28
     * @return ResourceLoader
     **/
    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }
    /**
     * @author hillchen
     * Description: 获取当前环境上下文
     * Date 2023/8/8 23:29
     * @return Environment
     **/
    public Environment getEnvironment() {
        return environment;
    }
}

